#include "WorkerThread.h"

// 实例化工作线程
WorkerThread::WorkerThread(int index) {
	_eventLoop = nullptr;
	_thread = nullptr;
	_threadID = thread::id();
	_name = "SubThread-" + to_string(index);
}

WorkerThread::~WorkerThread() {
	if (_thread != nullptr) { delete _thread; }
}

// 启动工作线程
void WorkerThread::run() {
	// 1. 创建子线程
	_thread = new thread(&WorkerThread::running, this);

	// 2. 阻塞主线程, 直到[子线程的反应堆模型]实例化完毕后再返回
	/* (1) workerThreadRun是由主线程调用的，当workerThreadRun()执行完毕后，子线程的回调函数subThreadRunning()中，
	*		子线程的反应堆可能没有完成实例化
	*  (2) 但workerThreadRun()执行结束后，主线程会认为子线程的反应堆模型已经实例化完成并启动了，此时主线程就
	*		认为自己可以从线程池中取出[子线程._eventLoop], 并且可以往[该_eventLoop.任务队列]中添加任务。但
	*		此时若[该子线程的反应堆]可能还没有实例化完成，则主线程往[子线程.反应堆.任务队列]中添加任务会出问题
	*  (3) ∴需要使用子线程的条件变量，来阻塞主线程，让主线程等待至[子线程._eventLoop]初始化完毕
	*/
	unique_lock<mutex> locker(_mutex);
	while (_eventLoop == nullptr) { _cond.wait(locker); }
}

/* [主线程调用的workerThreadRun()、子线程的回调函数subThreadRunning()]中关于互斥锁和条件变量的解读
*	   (1) 若主线程先获取子线程的锁资源: 主线程会进入while循环并阻塞等待条件变量满足，此时pthread_cond_wait()会
*   释放子线程的锁资源。则子线程即可获取锁资源并调用eventLoopInitEx()实例化反应堆，当实例化完成后，子线程会
*	释放锁资源，并调用pthread_cond_signal()让条件变量满足，使主线程解除阻塞并重新获取锁资源并向后执行
*	      ·保证了: workerThreadRun()结束时, 子线程的反应堆模型已实例化完毕
*	   (2) 子线程先获取了锁资源: 主线程会阻塞而没进入while循环，当子线程的反应堆实例化完毕后，子线程会释放锁资源，
*	此时主线程获取锁资源，但此时while循环的条件已不满足，主线程继续向后执行
*	      ·也保证了: workerThreadRun()结束时, 子线程的反应堆模型已实例化完毕
*/

// 工作线程的任务函数
void WorkerThread::running() {
	// 1. 实例化子线程的反应堆
	_mutex.lock();
	_eventLoop = new EventLoop(_name);
	_mutex.unlock();
	_cond.notify_one();

	// 2. 运行子线程的反应堆
	_eventLoop->run();
}